/**
 * 
 */
package coveranalyzer.handlers;

import java.util.Set;
import java.util.TreeSet;

/**
 * @author dongxu
 * 
 */
public class ReachablityAnalysisResult {

	public enum Reachablity {
		YES, NO, UN_KNOW
	}

	private Set<String> reachableTypes;

	private Set<String> unReachableTypes;

	private Set<String> reachableMethods;

	private Set<String> unReachableMethods;

	public ReachablityAnalysisResult(Set<String> initialReachableTypes) {
		reachableTypes = initialReachableTypes;
		unReachableTypes = new TreeSet<String>();
		reachableMethods = new TreeSet<String>();
		unReachableMethods = new TreeSet<String>();
	}

	public Reachablity isReachable(String elemStr) {
		if (isMethod(elemStr)) {
			return judgeReachability(elemStr, reachableMethods,
					unReachableMethods);
		} else if (isType(elemStr)) {
			return judgeReachability(elemStr, reachableTypes, unReachableTypes);
		} else {
			throw new RuntimeException(
					"ReachableAnalysisResult#isReachable: invalid element string");
		}
	}

	private Reachablity judgeReachability(String elemStr,
			Set<String> reachableSet, Set<String> unReachableSet) {
		if (reachableSet.contains(elemStr)) {
			return Reachablity.YES;
		} else if (unReachableSet.contains(elemStr)) {
			return Reachablity.NO;
		} else {
			return Reachablity.UN_KNOW;
		}
	}

	public void putReachableResult(String elemStr) {
		putResult(elemStr, false);
	}

	public void putUnReachableResult(String elemStr) {
		putResult(elemStr, true);
	}

	public void putResult(String elemStr, boolean reachable) {
		Set<String> typeDest = reachable ? reachableTypes : unReachableTypes;
		Set<String> typeOpposite = reachable ? unReachableTypes
				: reachableTypes;
		Set<String> methodDest = reachable ? reachableMethods
				: unReachableMethods;
		Set<String> methodOpposite = reachable ? unReachableMethods
				: reachableMethods;
		if (typeOpposite.contains(elemStr) || methodOpposite.contains(elemStr)) {
			throw new RuntimeException(
					"ReachableAnalysisResult#putResult: can not add a result into both reachable and un-reachable set");
		}
		if (isMethod(elemStr)) {
			methodDest.add(elemStr);
		} else if (isType(elemStr)) {
			typeDest.add(elemStr);
		} else {
			throw new RuntimeException(
					"ReachableAnalysisResult#putResult: invalid element string");
		}
	}

	private boolean isType(String result) {
		return result.matches("[^#]+#[^#]+");
	}

	private boolean isMethod(String result) {
		return result.matches("[^#]+#[^#]+#[^#]+");
	}

	public void reportInitialReachableTypes() {
		System.out.println(String.format("%d reachable types found",
				reachableTypes.size()));
	}
	
	public void reportUnReachableElements() {
		System.out.println(unReachableTypes);
		System.out.println(unReachableMethods);
	}
}



